package com.ww.springboot.es2.utils;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientProperties;
import org.springframework.boot.autoconfigure.elasticsearch.RestClientBuilderCustomizer;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.util.StringUtils;

import java.net.URI;
import java.net.URISyntaxException;

/**
 * 描述：
 *
 * @author 🧑 ‍wanwei
 * @since 2025-07-30 10:51
 */
public class ElasticsearchTemplateUtil {

    public static ElasticsearchRestTemplate build(ElasticsearchRestClientProperties properties) {
        RestClientBuilderCustomizer customizer = new ElasticsearchRestClientConfigurations.DefaultRestClientBuilderCustomizer(properties);
        RestClientBuilder restClientBuilder = elasticsearchRestClientBuilder(properties, customizer);
        RestHighLevelClient restHighLevelClient = elasticsearchRestHighLevelClient(restClientBuilder);
        ElasticsearchConverter elasticsearchConverter = elasticsearchConverter(new SimpleElasticsearchMappingContext());
        ElasticsearchRestTemplate elasticsearchRestTemplate = new ElasticsearchRestTemplate(restHighLevelClient, elasticsearchConverter);
        return elasticsearchRestTemplate;
    }

    private static ElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext) {
        return new MappingElasticsearchConverter(mappingContext);
    }

    private static RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
        return new RestHighLevelClient(restClientBuilder);
    }

    private static RestClient elasticsearchRestClient(RestClientBuilder builder,
                                       RestHighLevelClient client) {
        if (client != null) {
            return client.getLowLevelClient();
        }
        return builder.build();
    }

    private static RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties,
                                                                    RestClientBuilderCustomizer customizer) {
        HttpHost[] hosts = properties.getUris().stream().map(url -> createHttpHost(url)).toArray(HttpHost[]::new);
        RestClientBuilder builder = RestClient.builder(hosts);
        builder.setHttpClientConfigCallback((httpClientBuilder) -> {
            customizer.customize(httpClientBuilder);
            return httpClientBuilder;
        });
        builder.setRequestConfigCallback((requestConfigBuilder) -> {
            customizer.customize(requestConfigBuilder);
            return requestConfigBuilder;
        });
        customizer.customize(builder);
        return builder;
    }

    private static HttpHost createHttpHost(String uri) {
        try {
            return createHttpHost(URI.create(uri));
        } catch (IllegalArgumentException ex) {
            return HttpHost.create(uri);
        }
    }

    private static HttpHost createHttpHost(URI uri) {
        if (!StringUtils.hasLength(uri.getUserInfo())) {
            return HttpHost.create(uri.toString());
        }
        try {
            return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),
                    uri.getQuery(), uri.getFragment()).toString());
        } catch (URISyntaxException ex) {
            throw new IllegalStateException(ex);
        }
    }

}
